package com.qs.rocketmq.order.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.qs.rocketmq.common.util.ResultObject;
import com.qs.rocketmq.order.dto.CouponDTO;
import com.qs.rocketmq.order.dto.OrderDTO;
import com.qs.rocketmq.order.entity.Order;
import com.qs.rocketmq.order.entity.Transaction;
import com.qs.rocketmq.order.mapper.OrderMapper;
import com.qs.rocketmq.order.service.OrderService;
import com.qs.rocketmq.order.service.TransactionService;
import com.qs.rocketmq.order.util.OrderConstant;
import lombok.extern.slf4j.Slf4j;
import org.apache.rocketmq.client.producer.TransactionSendResult;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.messaging.Message;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.client.RestTemplate;

import java.math.BigDecimal;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

@Slf4j
@Service
public class OrderServiceImpl implements OrderService {

    @Autowired
    private OrderMapper orderMapper;

    @Autowired
    private RocketMQTemplate rocketMQTemplate;

    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private TransactionService transactionService;


    @Override
    public Order getById(String id) {
        return orderMapper.selectById(id);
    }

    public boolean existOrder(String orderSn) {
        QueryWrapper<Order> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("order_sn", orderSn);
        Order order = orderMapper.selectOne(queryWrapper);
        return order != null;
    }

    @Transactional
    @Override
    public ResultObject<Object> createOrder(OrderDTO orderDTO) {
        ResultObject<Object> resultObject = new ResultObject<>();
        // 根据couponId，获取券信息
        CouponDTO couponDTO = getCouponDTO(orderDTO.getCouponId());
        if (couponDTO.getAmount().intValue() <= 0) {
            log.error("券数量不足");
            resultObject.setErrorCode(10003L);
            return resultObject;
        }

        // 构建订单
        wrapOrderDTO(orderDTO, couponDTO);

        // 发送事务消息
        TransactionSendResult sendResult = sendTransactionMsg(orderDTO);
        log.info("事务消息发送结束：{}", sendResult);
        return resultObject;
    }

    private CouponDTO getCouponDTO(String couponId) {
        ResponseEntity<CouponDTO> responseEntity = restTemplate.getForEntity("http://localhost:9002/coupon/" + couponId, CouponDTO.class);
        return responseEntity.getBody();
    }

    private void wrapOrderDTO(OrderDTO orderDTO, CouponDTO couponDTO) {
        orderDTO.setOrderSn(IdWorker.getIdStr());
        orderDTO.setTotalAmount(new BigDecimal("1000.00"));
        if (couponDTO != null) {
            orderDTO.setCouponId(String.valueOf(couponDTO.getId()));
            orderDTO.setCouponAmount(couponDTO.getAmount());
            orderDTO.setPayAmount(orderDTO.getTotalAmount().subtract(couponDTO.getAmount()));
        }

        orderDTO.setCreateTime(new Date());
        orderDTO.setStatus("0");
    }

    private TransactionSendResult sendTransactionMsg(OrderDTO orderDTO) {
        String destination = OrderConstant.ORDER_TX_TOPIC + ":" + OrderConstant.ORDER_TX_TAG;
        Message<OrderDTO> message = MessageBuilder.withPayload(orderDTO)
                .setHeader("KEYS", OrderConstant.REQ_CODE_CREATE_ORDER)
                .build();
        Map<String, String> args = new HashMap<>();
        args.put("reqCode", OrderConstant.REQ_CODE_CREATE_ORDER);
        return rocketMQTemplate.sendMessageInTransaction(destination, message, args);
    }

    @Transactional
    @Override
    public ResultObject<Object> doCreateOrder(OrderDTO orderDTO) {
        ResultObject<Object> resultObject = new ResultObject<>();
        // 判断订单是否存在
        String orderSn = orderDTO.getOrderSn();
        if (existOrder(orderSn)) {
            resultObject.setErrorCode(1001L);
            resultObject.setMessage("订单已存在");
            return resultObject;
        }

        // 判断事务消息是否存在（幂等）
        String transactionId = orderDTO.getTransactionId();
        if (transactionService.checkTransactionStatus(transactionId)) {
            resultObject.setErrorCode(1002L);
            resultObject.setMessage("事务已存在");
            return resultObject;
        }

        try {
            // 保存事务消息记录
            log.info("开始保存事务记录");
            Transaction transaction = new Transaction();
            transaction.setTransactionId(transactionId);
            transaction.setCreateTime(new Date());
            transactionService.save(transaction);
            log.info("事务记录保存成功");

            // 新增订单记录
            log.info("开始保存订单");
            Order order = new Order();
            BeanUtil.copyProperties(orderDTO, order);
            orderMapper.insert(order);
            log.info("订单保存成功");
        } catch (Exception e) {
            log.error("保存事务记录、订单记录出现异常", e);
            resultObject.setErrorCodeWithTrans(9999L);
            resultObject.setMessage("保存事务记录、订单记录出现异常");
        }

        return resultObject;
    }
}
